﻿//
// Library: KwData
// File:    BtreeDictionaryObject.cs
// Purpose: Defines nongeneric API for BtreeDictionary and its Keys and Values sublcasses.
//
// Copyright © 2009-2012 Kasey Osborn (Kasewick@gmail.com)
// Ms-PL - Use and redistribute freely
//

using System;
using System.Collections;
using System.Diagnostics;

namespace Kw.Data
{
    public partial class BtreeDictionary<TKey, TValue>
    {
        #region Explicit object properties and methods

        void IDictionary.Add (object key, object value)
        {
            var genCol = (System.Collections.Generic.IDictionary<TKey, TValue>) this;
            genCol.Add ((TKey) key, (TValue) value);
        }


        bool IDictionary.Contains (object jKey)
        {
            var path = new TreePath<TKey, TValue> (this, (TKey) jKey);
            return path.IsFound;
        }


        void ICollection.CopyTo (Array array, int arrayIndex)
        {
            if (array == null)
                throw new ArgumentNullException ("array", "Value cannot be null.");

            if (array.Rank > 1)
                throw new ArgumentException ("Multi dimension array is not supported on this operation.");

            if (arrayIndex < 0)
                throw new ArgumentOutOfRangeException ("arrayIndex", "Index is less than zero.");

            if (arrayIndex + Count > array.Length)
                throw new ArgumentException ("Destination array is not long enough to copy all the items in the collection. Check array index and length.");

            if (!(array is System.Collections.Generic.KeyValuePair<TKey, TValue>[])
                & array.GetType () != typeof (object[]))
                throw new ArgumentException ("Target array type is not compatible with the type of items in the collection.");

            foreach (System.Collections.Generic.KeyValuePair<TKey, TValue> pair in this)
            {
                array.SetValue (pair, arrayIndex);
                ++arrayIndex;
            }
        }

        IDictionaryEnumerator IDictionary.GetEnumerator ()
        { return new BtreeObjectEnumerator (this); }


        IEnumerator IEnumerable.GetEnumerator ()
        { return ((IDictionary) this).GetEnumerator (); }

        /// <summary>Remove the supplied key and its associated value from the collection.</summary>
        /// <param name="key">Key to remove.</param>
        /// <exception cref="ArgumentNullException">When <em>key</em> is <b>null</b>.</exception>
        void IDictionary.Remove (object key)
        {
            if (key == null)
                throw new ArgumentNullException ("Value cannot be null.");

            var path = new TreePath<TKey, TValue> (this, (TKey) key);
            if (path.IsFound)
                Delete (path);
        }


        /// <summary>Deprecated.</summary>
        object ICollection.SyncRoot
        { get { return new System.Object (); } }

        #endregion


        public class BtreeObjectEnumerator : IDictionaryEnumerator
        {
            BtreeDictionary<TKey, TValue> target;
            Leaf<TKey, TValue> currentLeaf;
            int leafIndex;

            #region Constructors

            public BtreeObjectEnumerator (BtreeDictionary<TKey, TValue> newBtree)
            {
                target = newBtree;
                Reset ();
            }

            #endregion

            #region Properties

            public DictionaryEntry Entry { get { return new DictionaryEntry (Key, Value); } }
            public object Current { get { return Entry; } }
            public object Key { get { return currentLeaf.GetKey (leafIndex); } }
            public object Value { get { return currentLeaf.GetValue (leafIndex); } }

            #endregion

            #region Methods

            public bool MoveNext ()
            {
                if (++leafIndex < currentLeaf.KeyCount)
                    return true;

                leafIndex = 0;
                currentLeaf = currentLeaf.RightLeaf;
                return currentLeaf != null;
            }

            public void Dispose () { Dispose (true); GC.SuppressFinalize (this); }
            protected virtual void Dispose (bool disposing) { }
            public void Reset () { leafIndex = -1; currentLeaf = target.GetFirstLeaf (); }

            #endregion
        }

        #region Explicit properties and methods

        public object this[object key]
        {
            get
            {
                if (key == null)
                    throw new ArgumentNullException ("key", "Value cannot be null.");

                int index;
                Leaf<TKey, TValue> leaf = Find ((TKey) key, out index);
                if (index < 0)
                    return null;
                return leaf.GetValue (index);
            }
            set
            {
                if (key == null)
                    throw new ArgumentNullException ("key", "Value cannot be null.");

                var path = new TreePath<TKey, TValue> (this, (TKey) key);
                if (path.IsFound)
                    path.LeafValue = (TValue) value;
                else
                    Insert (path, (TKey) key, (TValue) value);
            }
        }

        bool IDictionary.IsFixedSize
        { get { return false; } }

        /// <summary>Indicate that structure may be modified.</summary>
        bool IDictionary.IsReadOnly
        { get { return false; } }

        bool ICollection.IsSynchronized
        { get { return false; } }

        ICollection IDictionary.Keys
        { get { return (ICollection) keys; } }

        ICollection IDictionary.Values
        { get { return (ICollection) values; } }

        #endregion


        public partial class BtreeKeys
        {
            #region Explicit object properties and methods

            void System.Collections.ICollection.CopyTo (Array array, int arrayIndex)
            {
                if (array == null)
                    throw new ArgumentNullException ("array", "Value cannot be null.");

                if (array.Rank > 1)
                    throw new ArgumentException ("Multi dimension array is not supported on this operation.");

                if (arrayIndex < 0)
                    throw new System.ArgumentOutOfRangeException ("arrayIndex", "Index is less than zero.");

                if (arrayIndex + Count > array.Length)
                    throw new ArgumentException ("Destination array is not long enough to copy all the items in the collection. Check array index and length.");

                foreach (TKey key in this)
                {
                    array.SetValue (key, arrayIndex);
                    ++arrayIndex;
                }
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
            { return GetEnumerator (); }

            bool System.Collections.ICollection.IsSynchronized { get { return false; } }

            object System.Collections.ICollection.SyncRoot
            { get { return ((System.Collections.ICollection) tree).SyncRoot; } }

            #endregion
        }


        public partial class BtreeValues
        {
            #region Explicit object properties and methods

            void System.Collections.ICollection.CopyTo (Array array, int arrayIndex)
            {
                if (array == null)
                    throw new ArgumentNullException ("array", "Value cannot be null.");

                if (array.Rank > 1)
                    throw new ArgumentException ("Multi dimension array is not supported on this operation.");

                if (arrayIndex < 0)
                    throw new System.ArgumentOutOfRangeException ("arrayIndex", "Index is less than zero.");

                if (arrayIndex + Count > array.Length)
                    throw new ArgumentException ("Destination array is not long enough to copy all the items in the collection. Check array index and length.");

                foreach (TValue value in this)
                {
                    array.SetValue (value, arrayIndex);
                    ++arrayIndex;
                }
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
            { return GetEnumerator (); }

            bool System.Collections.ICollection.IsSynchronized
            { get { return false; } }

            object System.Collections.ICollection.SyncRoot
            { get { return ((System.Collections.ICollection) tree).SyncRoot; } }

            #endregion
        }
    }
}
